﻿#include "C3fdMeshControlWidget.h"
#include "ui_C3fdMeshControlWidget.h"
#include <QDebug>
#include <QFile>
#include <QMessageBox>
#include <cmath>
#include <QDir>

namespace MainWidget
{
	C3fdMeshControlWidget::C3fdMeshControlWidget(QTreeWidgetItem *rowItem, QWidget *parent)
		: QWidget(parent), m_Ui(new Ui::C3fdMeshControlWidget), m_Project(Common::C3fdProject::instance())
	{
		m_Ui->setupUi(this);
		connect(&m_Process, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessOutput()));
		connect(&m_Process, SIGNAL(readyReadStandardError()), this, SLOT(readAllStandardErrorSlot()));
		connect(&m_Process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));

		blockSignals(true);

		if (rowItem != nullptr)
		{

			QString casePath = m_Project->getCurrentProjectDir();
			QString rowNumStr = rowItem->text(0).mid(3, -1).simplified();

			auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();
			if (currentCase != nullptr)
			{
				bool ok;
				int rowNum = rowNumStr.toInt(&ok);
				if (ok)
				{
					m_BladeRow = currentCase->getBladeRowByRowNum(rowNum);
					if (m_BladeRow != nullptr)
					{
						m_Ui->dsb_Gap->setValue(m_BladeRow->getGap());
						m_Ui->dsb_RootFillet->setValue(m_BladeRow->getRootFillet());
						m_Ui->dsb_TipFillet->setValue(m_BladeRow->getTipFillet());
						switch (int(m_BladeRow->getUnitRadio() * 1000))
						{
						case 1000:
							m_Ui->comb_Unit->setCurrentIndex(0);
							break;
						case 100:
							m_Ui->comb_Unit->setCurrentIndex(1);
							break;
						case 10:
							m_Ui->comb_Unit->setCurrentIndex(2);
							break;
						case 1:
						default:
							m_Ui->comb_Unit->setCurrentIndex(3);
							break;
						}
						m_Ui->comb_BladeType->setCurrentIndex(m_BladeRow->getType() == Common::BladeRowType::Stator ? 0 : 1);
					}
				}
			}
		}

		m_Ui->dsb_Gap->setRange(0, DBL_MAX);
		m_Ui->dsb_RootFillet->setRange(0, DBL_MAX);
		m_Ui->dsb_TipFillet->setRange(0, DBL_MAX);
		blockSignals(false);
	}

	C3fdMeshControlWidget::~C3fdMeshControlWidget()
	{
		delete m_Ui;
	}

	void C3fdMeshControlWidget::on_comb_BladeType_currentIndexChanged(int index)
	{
		if (m_BladeRow != nullptr)
		{
			m_BladeRow->setType(m_Ui->comb_BladeType->currentIndex() == 0 ? Common::BladeRowType::Stator : Common::BladeRowType::Rotor);
		}
	}

	void C3fdMeshControlWidget::on_dsb_Gap_editingFinished()
	{
		if (m_BladeRow != nullptr)
		{
			m_BladeRow->setGap(m_Ui->dsb_Gap->value());
		}
	}

	void C3fdMeshControlWidget::on_dsb_RootFillet_editingFinished()
	{
		if (m_BladeRow != nullptr)
		{
			m_BladeRow->setRootFillet(m_Ui->dsb_RootFillet->value());
		}
	}

	void C3fdMeshControlWidget::on_dsb_TipFillet_editingFinished()
	{
		if (m_BladeRow != nullptr)
		{
			m_BladeRow->setTipFillet(m_Ui->dsb_TipFillet->value());
		}
	}

	void C3fdMeshControlWidget::on_pb_Save_clicked()
	{
		if (m_BladeRow == nullptr)
		{
			return;
		}

		m_BladeRow->setType(m_Ui->comb_BladeType->currentIndex() == 0 ? Common::BladeRowType::Stator : Common::BladeRowType::Rotor);
		m_BladeRow->setGap(m_Ui->dsb_Gap->value());
		m_BladeRow->setRootFillet(m_Ui->dsb_RootFillet->value());
		m_BladeRow->setTipFillet(m_Ui->dsb_TipFillet->value());
		m_BladeRow->setUnitRadio(0.001 * std::pow(10, 3 - m_Ui->comb_Unit->currentIndex()));
	}

	void C3fdMeshControlWidget::on_pb_GenerateMesh_clicked()
	{
		if (m_BladeRow == nullptr)
		{
			return;
		}

		QString casePath = m_Project->getCurrentProjectDir();

		QFile iMeshControlFile(casePath + m_Project->getMeshDirName() + QDir::separator() + m_Project->getMeshControlFileName());
		if (!iMeshControlFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
		{
			QMessageBox::critical(this, tr("Error Info"), QString(tr("Failed to open file: %1!")).arg(m_Project->getMeshControlFileName()));
			return;
		}

		int numOfSeries = 0;

		auto *currentCase = m_Project->getCurrentCase();
		if (currentCase == nullptr)
		{
			return;
		}

		auto totalRows = currentCase->getBladeRows();
		auto totalRowNum = totalRows.size();

		auto* reportData = currentCase->getReportData();
		if (reportData == nullptr) {
			return;
		}

		QString names = "", strHs = "", props = "", stators = "\n0";
		for (int r = 0; r < totalRowNum; ++r)
		{
			int rowNum = totalRows.at(r)->getRowNum();
			if (rowNum < 3)
			{
				numOfSeries = 1;
			}
			else
			{
				Common::BladeRowType firstRowBladeType = m_Project->getCurrentCase()->getBladeRowByRowNum(1)->getType();
				// 第一排为静子
				if (firstRowBladeType == Common::BladeRowType::Stator)
				{
					numOfSeries = std::ceil(float(rowNum - 1) / 2);
				}
				// 第一排为转子
				else if (firstRowBladeType == Common::BladeRowType::Rotor)
				{
					numOfSeries = std::ceil(float(rowNum) / 2);
				}
				// 错误格式，不应该执行到此处
				else
				{
					QMessageBox::critical(this, tr("Error Info"), tr("System Error!"));
					return;
				}
			}
			names += QString("\n%1").arg(totalRows.at(r)->getGeomFileName());
			auto strH = QString("H%1%2").arg(numOfSeries < 10 ? QString("0%1").arg(numOfSeries) : QString("%1").arg(numOfSeries)).arg(totalRows.at(r)->getType() == Common::BladeRowType::Stator ? "S" : "R");
			strHs += QString("\n%1").arg(strH);
			props += QString("\n%1  %2 %3 %4")
				.arg(totalRows.at(r)->getType() == Common::BladeRowType::Stator ? 0 : 1)
				.arg(totalRows.at(r)->getGap())
				.arg(totalRows.at(r)->getRootFillet())
				.arg(totalRows.at(r)->getTipFillet());
			reportData->addBladeRowData(strH, totalRows.at(r)->getBladeNum(), totalRows.at(r)->getGap(), 0);
		}

		// 生成MeshControl文件
		QTextStream fileMeshControl(&iMeshControlFile);
		QString meshControl = QString("tandem\n%1\n%2%3%4%5%6")
			.arg(m_BladeRow->getUnitRadio())
			.arg(totalRowNum)
			.arg(names)
			.arg(strHs)
			.arg(props)
			.arg(stators);
		fileMeshControl << meshControl;
		fileMeshControl.flush();
		iMeshControlFile.close();

		// 调用MESH.exe划分网格
		QString meshEXE = m_Project->getMeshExeFilePath();
		if (!QFile::exists(meshEXE))
		{
			QMessageBox::critical(this, tr("Error Info"), QString(tr("No found %1!").arg(meshEXE)));
			return;
		}
#if 0
		// 网格程序调用方式 MESH.exe -geo F:\stator35.geomTurbo -mc D:\Imesh_control.dat -dir D:\temp
		auto meshDirName = m_Project->getMeshDirName();
		QString startProcess = QString("%1 -geo %2 -mc %3 -dir %4")
			.arg(meshEXE)
			.arg(casePath + meshDirName + QDir::separator() + m_BladeRow->getGeomFileName())
			.arg(casePath + meshDirName + QDir::separator() + m_Project->getMeshControlFileName())
			.arg(casePath + meshDirName + QDir::separator());
#else

		QString startProcess = casePath + m_Project->getMeshDirName() + QDir::separator() + "mesh.bat";
		QFile meshBatFile(startProcess);
		if (meshBatFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
		{
			QTextStream meshBat(&meshBatFile);
			meshBat << meshEXE;
			meshBatFile.close();
		}
		m_Process.setWorkingDirectory(casePath + m_Project->getMeshDirName());
#endif // 0
		m_Process.start(startProcess);
	}

	void C3fdMeshControlWidget::processFinished(int, QProcess::ExitStatus exitStatus)
	{
		switch (exitStatus)
		{
		case QProcess::NormalExit:
		{
			QString meshDir = m_Project->getCurrentProjectDir() + m_Project->getMeshDirName() + QDir::separator();
			QFile reportFile(meshDir + m_Project->getMeshReportFileName());
			if (!reportFile.exists())
			{
				QMessageBox::critical(this, tr("Error Info"), QString(tr("No found %1!").arg(reportFile.fileName())));
				return;
			}
			if (!reportFile.open(QIODevice::ReadOnly | QIODevice::Text))
			{
				emit sendMessage(tr("Failed to open file: mesh/Omesh_report.dat"));
				return;
			}
			QTextStream report(&reportFile);
			QString line = report.readLine();
			int meshSizeIndex = -1;
			int totalRow = 0;
			QList<int> meshSizes = {};
			bool ok;
			while (!line.isNull())
			{
				if (line.toLower().simplified().startsWith("number of blade rows")) {
					totalRow = line.mid(20).replace("=", "").trimmed().toInt(&ok);
					if (!ok) {
						totalRow = 0;
					}
				}
				if (meshSizeIndex > -1 && totalRow > 0) {
					auto strs = line.split(" ", QString::SplitBehavior::SkipEmptyParts);
					if (strs.size() > meshSizeIndex)
					{
						auto size = strs.at(meshSizeIndex).toInt(&ok);
						if (ok) {
							meshSizes.push_back(size);
						}
						else {
							emit sendMessage(tr("Error data format!"));
							return;
						}
					}
					else {
						emit sendMessage(tr("Error data format!"));
						return;
					}
					--totalRow;
				}
				if (line.toUpper().startsWith("ROW_NO.")) {
					meshSizeIndex = line.split(" ", QString::SplitBehavior::SkipEmptyParts).indexOf("MESH_SIZE");
				}
				emit sendMessage(line);
				line = report.readLine();
			}
			reportFile.close();

			auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();
			if (currentCase != nullptr)
			{
				auto* reportData = currentCase->getReportData();
				if (reportData != nullptr) {
					if (!reportData->updateBladeRowMeshNum(meshSizes))
					{
						emit sendMessage(tr("Failed to update number of mesh: different blade rows!"));
					}
				}
			}


			// rendermesh
			QStringList meshFiles = {
				meshDir + m_Project->getMesh3DFileName(),
				meshDir + m_Project->getMeshS2FileName(),
				meshDir + m_Project->getMeshB2bHubFileName(),
				meshDir + m_Project->getMeshB2bMidFileName(),
				meshDir + m_Project->getMeshB2bTipFileName() };

			for (auto file : meshFiles)
			{
				if (!QFile::exists(file))
				{
					QMessageBox::critical(this, tr("Error Info"), QString(tr("No found %1!").arg(file)));
					return;
				}
			}


			emit renderC3fdMeshSig(meshFiles);
		}
		break;
		case QProcess::CrashExit:
			emit sendMessage("************************************");
			emit sendMessage("********* Mesh Crashed ************");
			emit sendMessage("************************************");
			break;
		default:
			emit sendMessage("***********************************");
			emit sendMessage("********* Mesh Stopped ************");
			emit sendMessage("***********************************");
			break;
		}
	}

	void C3fdMeshControlWidget::readProcessOutput()
	{
		QString outputBuffer = QString::fromLocal8Bit(m_Process.readAll());
		emit sendMessage(outputBuffer);
	}

	void C3fdMeshControlWidget::readAllStandardErrorSlot()
	{
		QString outputBuffer = QString::fromLocal8Bit(m_Process.readAllStandardError());
		emit sendMessage(outputBuffer);
	}

}